`timescale 1ns / 1ps

//----------------------------------------------------------------------------
// Local Defines.
//----------------------------------------------------------------------------

// Response Type Defines
`define RESPONSE_OKAY   2'b00
`define RESPONSE_EXOKAY 2'b01
`define RESPONSE_SLVERR 2'b10
`define RESPONSE_DECERR 2'b11

// AMBA AXI 4 Lite Range Constants
`define MAX_BURST_LENGTH 1
`define MAX_DATA_SIZE (DATA_BUS_WIDTH*`MAX_BURST_LENGTH)/8
   
// AMBA AXI 4 Lite Bus Size Constants
`define PROT_BUS_WIDTH 3
`define RESP_BUS_WIDTH 2

// Define for intenal control value
`define ADDRVALID_FALSE 0
`define ADDRVALID_TRUE  1

//----------------------------------------------------------------------------
// Create the testbench.
//----------------------------------------------------------------------------

module axi4_lite_master #(
   parameter NAME = "MASTER_0",
   parameter DATA_BUS_WIDTH = 32,
   parameter ADDRESS_BUS_WIDTH = 32,
   parameter MAX_OUTSTANDING_TRANSACTIONS = 8
)(
  input                           ACLK,
  input                           ARESETn,
  output  [ADDRESS_BUS_WIDTH-1:0] AWADDR,
  output  [2:0]                   AWPROT,
  output                          AWVALID,
  input                           AWREADY,
  output  [DATA_BUS_WIDTH-1:0]    WDATA,
  output  [DATA_BUS_WIDTH/8-1:0]  WSTRB,
  output                          WVALID,
  input                           WREADY,
  input   [1:0]                   BRESP,
  input                           BVALID,
  output                          BREADY,
  output  [ADDRESS_BUS_WIDTH-1:0] ARADDR,
  output  [2:0]                   ARPROT,
  output                          ARVALID,
  input                           ARREADY,
  input   [DATA_BUS_WIDTH-1:0]    RDATA,
  input   [1:0]                   RRESP,
  input                           RVALID,
  output                          RREADY
);

  cdn_axi4_lite_master_bfm #(
    NAME,
    DATA_BUS_WIDTH,
    ADDRESS_BUS_WIDTH,
    MAX_OUTSTANDING_TRANSACTIONS)
  master(
    .ACLK     (ACLK),
    .ARESETn  (ARESETn),
    // Write Address Channel
    .AWADDR   (AWADDR),
    .AWPROT   (AWPROT),
    .AWVALID  (AWVALID),
    .AWREADY  (AWREADY),
    // Write Data Channel Signals.
    .WDATA    (WDATA),
    .WSTRB    (WSTRB), 
    .WVALID   (WVALID),
    .WREADY   (WREADY),
    // Write Response Channel Signals.
    .BRESP    (BRESP),
    .BVALID   (BVALID),
    .BREADY   (BREADY),
    // Read Address Channel Signals.
    .ARADDR   (ARADDR),
    .ARPROT   (ARPROT),
    .ARVALID  (ARVALID),
    .ARREADY  (ARREADY),
    // Read Data Channel Signals.
    .RDATA    (RDATA),
    .RRESP    (RRESP),
    .RVALID   (RVALID),
    .RREADY   (RREADY));
/*    
task RegReadByte;
  input [31:0] Address;
  output [7:0] Data;
  reg [31:0] Value;
  reg [1:0] Response;
  begin
    master.READ_BURST(Address, 3'b0, Value, Response);
    CHECK_RESPONSE_OKAY(Response);
    case (Address[1:0])
      2'b00: Data = Value[7:0];
      2'b01: Data = Value[15:8];
      2'b10: Data = Value[23:16];
      2'b11: Data = Value[31:24];
    endcase
  end
endtask

task RegReadWord;
  input [31:0] Address;
  output [15:0] Data;
  reg [31:0] Value;
  reg [1:0] Response;
  begin
    if (Address[0])
    begin
      $display("Address is not Word Aligned");
      $stop;
    end
    master.READ_BURST(Address, 3'b0, Value, Response);
    CHECK_RESPONSE_OKAY(Response);
    case (Address[0])
      1'b0: Data = Value[15:0];
      1'b1: Data = Value[31:16];
    endcase
  end
endtask

task RegReadDWord;
  input [31:0] Address;
  output [15:0] Data;
  reg [31:0] Value;
  reg [1:0] Response;
  begin
    if (Address[1:0])
    begin
      $display("Address is not DWord Aligned");
      $stop;
    end
    master.READ_BURST(Address, 3'b0, Value, Response);
    CHECK_RESPONSE_OKAY(Response);
    Data = Value;
  end
endtask

task RegWriteByte;
  input [31:0] Address;
  input [7:0] Data;
  reg [1:0] Response;
  begin
    master.WRITE_BURST_CONCURRENT(Address, 3'b0, Data, 1, Response);
    CHECK_RESPONSE_OKAY(Response);
  end
endtask

task RegWriteWord;
  input [31:0] Address;
  input [15:0] Data;
  reg [1:0] Response;
  begin
    if (Address[0])
    begin
      $display("Address is not Word Aligned");
      $stop;
    end
    master.WRITE_BURST_CONCURRENT(Address, 3'b0, Data, 2, Response);
    CHECK_RESPONSE_OKAY(Response);
  end
endtask

task RegWriteDWord;
  input [31:0] Address;
  input [31:0] Data;
  reg [1:0] Response;
  begin
    if (Address[1:0])
    begin
      $display("Address is not DWord Aligned");
      $stop;
    end
    master.WRITE_BURST_CONCURRENT(Address, 3'b0, Data, 4, Response);
    CHECK_RESPONSE_OKAY(Response);
  end
endtask
*/    
endmodule

module  pcie_stream_master #(
   parameter NAME = "PCIE_MASTER",
   parameter DATA_BUS_WIDTH = 32,
   parameter MAX_PAYLOAD_SIZE = 128
)(
  input                           ACLK,
  input                           ARESETn,
  output                          TVALID,
  input                           TREADY,
  output  [DATA_BUS_WIDTH-1:0]    TDATA,
  output  [DATA_BUS_WIDTH/8-1:0]  TKEEP,
  output  [DATA_BUS_WIDTH/8-1:0]  TSTRB,
  output                          TLAST
);

  localparam MAX_PACKET_SIZE = (16 + MAX_PAYLOAD_SIZE + 4) / (DATA_BUS_WIDTH/8);
  localparam USER_BUS_WIDTH = 1;
  
  cdn_axi4_streaming_master_bfm #(
    .NAME(NAME),
    .DATA_BUS_WIDTH(DATA_BUS_WIDTH),
    .ID_BUS_WIDTH(0),
    .DEST_BUS_WIDTH(0),
    .USER_BUS_WIDTH(USER_BUS_WIDTH),
    .MAX_PACKET_SIZE(MAX_PACKET_SIZE),
    .STROBE_NOT_USED(0),
    .KEEP_NOT_USED(0))
  axis_master(
    .ACLK    (ACLK),
    .ARESETn (ARESETn),
    // Transfer Channel
    .TVALID (TVALID),
    .TREADY (TREADY),
    .TDATA  (TDATA),
    .TSTRB  (TSTRB),
    .TKEEP  (TKEEP),
    .TLAST  (TLAST),
    .TID    (TID),
    .TDEST  (TDEST),
    .TUSER  (TUSER));
    
  task SendRandomPacket;
   reg [(DATA_BUS_WIDTH*(MAX_PACKET_SIZE))-1:0] v_mtestDATA;
   reg [(USER_BUS_WIDTH*(MAX_PACKET_SIZE))-1:0] v_mtestUSER;
   integer                      mtestDATASIZE;
   integer i, j;
  begin
    mtestDATASIZE = 16*4;
      for (j=0; j < ((DATA_BUS_WIDTH*(MAX_PACKET_SIZE))/8); j=j+1) begin
         v_mtestDATA[j*8 +: 8] = j;
      end

      for (j=0; j < ((USER_BUS_WIDTH*(MAX_PACKET_SIZE))/8); j=j+1) begin
         v_mtestUSER[j*8 +: 8] = j;
      end
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*4, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*3 + 4, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*3 + 8, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*3 + 12, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*8 + 4, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*8 + 8, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*8 + 12, v_mtestUSER);
    axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*4, v_mtestUSER);
    for (i = 0; i<200; i++)
      axis_master.SEND_PACKET(0, 0, v_mtestDATA, 16*8, v_mtestUSER);
    
  end
  endtask

endmodule

module pcie_stream_slave #(
   parameter NAME = "PCIE_SLAVE",
   parameter DATA_BUS_WIDTH = 32,
   parameter MAX_PAYLOAD_SIZE = 128
)(
  input                           ACLK,
  input                           ARESETn,
  output                          TVALID,
  output                          TREADY,
  input   [DATA_BUS_WIDTH-1:0]    TDATA,
  input   [DATA_BUS_WIDTH/8-1:0]  TKEEP,
  input                           TLAST
);
  
  localparam MAX_PACKET_SIZE = (16 + MAX_PAYLOAD_SIZE + 4) / (DATA_BUS_WIDTH/8);
  cdn_axi4_streaming_slave_bfm #(
    .NAME(NAME),
    .DATA_BUS_WIDTH(DATA_BUS_WIDTH),
    .ID_BUS_WIDTH(0),
    .DEST_BUS_WIDTH(0),
    .USER_BUS_WIDTH(0),
    .MAX_PACKET_SIZE(MAX_PACKET_SIZE),
    .STROBE_NOT_USED(1),
    .KEEP_NOT_USED(0))
  axis_slave(
    .ACLK    (ACLK),
    .ARESETn (ARESETn),
    // Transfer Channel
    .TVALID (TVALID),
    .TREADY (TREADY),
    .TDATA  (TDATA),
    .TSTRB  (TSTRB),
    .TKEEP  (TKEEP),
    .TLAST  (TLAST),
    .TID    (TID),
    .TDEST  (TDEST),
    .TUSER  (TUSER));
endmodule
